package com.fp.m7.server.helpers;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spring4gwt.server.SpringGwtRemoteServiceServlet;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCServletUtils;
import com.google.gwt.user.server.rpc.impl.StandardSerializationPolicy;

public class CustomSpringGwtRemoteServiceServlet extends SpringGwtRemoteServiceServlet {
    private static final long serialVersionUID = 4612953053778951749L;

    private static final Logger logger = LoggerFactory.getLogger(CustomSpringGwtRemoteServiceServlet.class);

    private StandardSerializationPolicy preprocessingExceptionPolicy;

    public CustomSpringGwtRemoteServiceServlet() {
        Map<Class<?>, Boolean> exceptionMap = new HashMap<Class<?>, Boolean>();
        exceptionMap.put(InsufficientAuthenticationException.class, true);
        exceptionMap.put(BadCredentialsException.class, true);
        exceptionMap.put(UsernameNotFoundException.class, true);
        exceptionMap.put(AuthenticationException.class, true);
        exceptionMap.put(RuntimeException.class, false);
        exceptionMap.put(Exception.class, false);
        exceptionMap.put(Throwable.class, false);

        preprocessingExceptionPolicy = new StandardSerializationPolicy(exceptionMap, exceptionMap,
                new HashMap<Class<?>, String>());
    }

    @Override
    protected void doUnexpectedFailure(Throwable throwable) {
        if (throwable instanceof AuthenticationException) {
            try {
                String responseStr = RPC.encodeResponseForFailure(null, throwable, preprocessingExceptionPolicy);
                RPCServletUtils.writeResponse(getServletContext(), getThreadLocalResponse(), responseStr, false);
            } catch (SerializationException e) {
                logger.info("Serialization exception.", e);
            } catch (IOException e) {
                logger.info("IOException.", e);
            }

        } else {
            super.doUnexpectedFailure(throwable);
        }
    }
}
